package cn.uncode.springcloud.starter.web.result;

import java.util.HashMap;

import org.apache.commons.lang3.StringUtils;

import cn.uncode.springcloud.utils.obj.BeanUtil;
import io.swagger.annotations.ApiModel;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

/**
 * 统一API响应结果封装
 *
 * @author Juny
 */
@Getter
@Setter
@ToString
@ApiModel(description = "返回信息")
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class R<T> extends HashMap<String, Object> {

	private static final long serialVersionUID = 1L;

	private static String CODE_KEY = RConstant.DEFAULT_RESULT_CODE_KEY;
	private static String MESSAGE_KEY = RConstant.DEFAULT_RESULT_MESSAGE_KEY;
	private static String DATA_KEY = RConstant.DEFAULT_RESULT_DATA_KEY;
	private static String SUCCESS_KEY = null;
	private static String PAGE_KEY = RConstant.DEFAULT_RESULT_PAGE_KEY;
	private static int SUCCESS_CODE = ResultCode.SUCCESS.getCode();
	private static int FAILURE_CODE = ResultCode.FAILURE.getCode();
	
	
	public static void setCodeKeys(String codeKey, String messageKey, String dataKey, String successKey) {
		if(StringUtils.isNotBlank(codeKey))CODE_KEY = codeKey;
		if(StringUtils.isNotBlank(messageKey))MESSAGE_KEY = messageKey;
		if(StringUtils.isNotBlank(dataKey))DATA_KEY = dataKey;
		if(StringUtils.isNotBlank(successKey))SUCCESS_KEY = successKey;
	}
	
	public static void setDefaultSuccessCode(int successCode) {
		SUCCESS_CODE = successCode;
	}
	
	public static void setDefaultFailureCode(int failureCode) {
		FAILURE_CODE = failureCode;
	}
	
	public int getResultCode() {
		String code = String.valueOf(this.get(CODE_KEY));
		return Integer.parseInt(code);
	}
	
	public String getResultMessage() {
		String msg = String.valueOf(this.get(MESSAGE_KEY));
		return msg;
	}


	private R(ResultCode resultCode) {
		this(resultCode.getCode(), resultCode.getMessage());
	}

	private R(ResultCode resultCode, String msg) {
		this(resultCode.getCode(), msg);
	}

	private R(ResultCode resultCode, T data) {
		this(resultCode, data, resultCode.getMessage());
	}

	private R(ResultCode resultCode, T data, String msg) {
		this(resultCode.getCode(), data, msg);
	}



	private R(int code, String message) {
		this.put(CODE_KEY, code);
		this.put(MESSAGE_KEY, message);
		appendSuccess(code);
	}

	private void appendSuccess(int code) {
		if(StringUtils.isNotBlank(SUCCESS_KEY)) {
			if(code >= 200 && code < 300) {
				this.put(SUCCESS_KEY, true);
			}else {
				this.put(SUCCESS_KEY, false);
			}
		}
	}

	private R(int code, T data, String message) {
		this.put(CODE_KEY, code);
		this.put(MESSAGE_KEY, message);
		this.put(DATA_KEY, data);
		appendSuccess(code);
	}
	
	private R(int code, P<T> page, String message) {
		this.put(CODE_KEY, code);
		this.put(MESSAGE_KEY, message);
		this.put(DATA_KEY, page.getData());
		this.put(PAGE_KEY, page.getPage());
		appendSuccess(code);
	}

	/**
	 * 返回R
	 *
	 * @param code 状态码
	 * @param data 数据
	 * @param msg  消息
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(int code, T data, String msg) {
		return new R<>(code, data, data == null ? RConstant.DEFAULT_NULL_MESSAGE : msg);
	}

	/**
	 * 返回R
	 *
	 * @param data 数据
	 * @param msg  消息
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(T data, String msg) {
		return success(SUCCESS_CODE, data, msg);
	}
	
	public static <T> R<T> success(P<T> page, String msg) {
		return new R<T>(SUCCESS_CODE, page, msg);
	}

	/**
	 * 返回R
	 *
	 * @param data 数据
	 * @param resultCode  rcode
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(T data, ResultCode resultCode) {
		return success(resultCode.getCode(), data, resultCode.getMessage());
	}

	/**
	 * 返回R
	 *
	 * @param data 数据
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(T data) {
		return success(data, RConstant.DEFAULT_SUCCESS_MESSAGE);
	}
	
	public static <T> R<T> success() {
		return success(RConstant.DEFAULT_SUCCESS_MESSAGE);
	}
	
	public static <T> R<T> success(P<T> page) {
		return success(page, RConstant.DEFAULT_SUCCESS_MESSAGE);
	}

	/**
	 * 返回R
	 *
	 * @param msg 消息
	 * @param <T> T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(String msg) {
		return new R<>(SUCCESS_CODE, msg);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(ResultCode resultCode) {
		return new R<>(resultCode);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param msg        消息
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> success(ResultCode resultCode, String msg) {
		return new R<>(resultCode, msg);
	}

	/**
	 * 返回R
	 *
	 * @param msg 消息
	 * @param <T> T 泛型标记
	 * @return R
	 */
	public static <T> R<T> failure(String msg) {
		return new R<>(FAILURE_CODE, msg);
	}
	
	public static <T> R<T> failure() {
		return new R<>(FAILURE_CODE, RConstant.DEFAULT_FAILURE_MESSAGE);
	}


	/**
	 * 返回R
	 *
	 * @param code 状态码
	 * @param msg  消息
	 * @param <T>  T 泛型标记
	 * @return R
	 */
	public static <T> R<T> failure(int code, String msg) {
		return new R<>(code, msg);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> failure(ResultCode resultCode) {
		return new R<>(resultCode);
	}

	/**
	 * 返回R
	 *
	 * @param resultCode 业务代码
	 * @param msg        消息
	 * @param <T>        T 泛型标记
	 * @return R
	 */
	public static <T> R<T> failure(ResultCode resultCode, String msg) {
		return new R<>(resultCode, msg);
	}
	
	/**
	 * 空
	 * @return
	 */
	public static <T> R<T> none() {
		return new R<>();
	}
	
	
	/**
	 * 需要扩展属性时使用
	 * @param key 属性名
	 * @param value 属性值
	 * @return R
	 */
	public R<T> fill(String key, Object value) {
		this.put(key, value);
		return this;
	}
	
	/**
	 * 自定义属性【谨慎使用】 <br/>
	 * 将覆盖所有底层框架值
	 * @param value 返回值
	 * @return R
	 */
	public R<T> fill(Object value) {
		this.putAll(BeanUtil.toMap(value));
		return this;
	}


}
